package com.xyy.saas.payment.callback.core.handler;

import com.alibaba.fastjson.JSON;
import com.xyy.saas.payment.adpater.pingxx.domain.RefundDO;
import com.xyy.saas.payment.api.impl.PaymentOrderApiImpl;
import com.xyy.saas.payment.callback.core.result.CallbackRunner;
import com.xyy.saas.payment.common.Constants;
import com.xyy.saas.payment.common.RocketMqTopic;
import com.xyy.saas.payment.cores.bo.SeparateAccountsBo;
import com.xyy.saas.payment.cores.enums.BusinessIdTypeEnum;
import com.xyy.saas.payment.cores.enums.BusinessTypeEnum;
import com.xyy.saas.payment.cores.enums.ChannelTypeEnum;
import com.xyy.saas.payment.cores.enums.CommonStatusEnum;
import com.xyy.saas.payment.cores.vo.CallbackResultVo;
import com.xyy.saas.payment.cores.vo.ResultVO;
import com.xyy.saas.payment.cores.vo.SeparateAccountFromUserVo;
import com.xyy.saas.payment.dao.mapper.PayResultOrderMapper;
import com.xyy.saas.payment.dao.mapper.RefundOrderMapper;
import com.xyy.saas.payment.dao.model.PayResultOrder;
import com.xyy.saas.payment.dao.model.RefundOrder;
import com.xyy.saas.payment.dao.model.RefundReturnAdvance;
import com.xyy.saas.payment.merchant.core.dto.RechargeHandleDto;
import com.xyy.saas.payment.service.RefundReturnAdvanceService;
import com.xyy.saas.payment.util.JSONUtils;
import com.xyy.saas.payment.util.LeafUtil;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * @author wangtianqi
 * @date 2019/10/22 11:16
 */
@Component
public class OrderRefundHandler implements BaseHandler {

    private static final org.slf4j.Logger LOGGER = org.slf4j.LoggerFactory.getLogger(OrderRefundHandler.class);

    @Autowired
    private RefundOrderMapper refundDomainMapper;
    @Autowired
    private CallbackRunner callbackRunner;
    @Autowired
    private PayResultOrderMapper payResultOrderMapper;
    @Autowired
    private RefundReturnAdvanceService refundReturnAdvanceService;
    @Autowired
    private LeafUtil leafUtil;
    @Resource
    private PaymentOrderApiImpl paymentOrderApi;

    @Override
    public String getMethod() {
        return Constants.METHOD_REFUND_SUCCESS;
    }

    @Override
    public boolean callBackHandler(Object domain) {
        LOGGER.info("OrderRefundSuccessHandler#callBackHandler RefundDO:{}", JSON.toJSONString(domain));

        try {
            RefundDO refundDO = (RefundDO) domain;

            if(StringUtils.isEmpty(refundDO.getId())) {
                LOGGER.error("OrderRefundSuccessHandler#callBackHandler refund id is empty error refundDO:{}", JSON.toJSONString(refundDO));
                return true;
            }

            RefundOrder refundOrder = refundDomainMapper.selectByChannelRefundNo(refundDO.getPayNo(), refundDO.getId());

            if(refundOrder != null && RefundOrder.STATUS_FINISH.equals(refundOrder.getStatus())) {
                LOGGER.warn("OrderRefundSuccessHandler#callBackHandler refund is finish refundDO Id:{}", refundDO.getId());
                return true;
            }

            if(refundOrder == null) {
                if(StringUtils.isEmpty(refundDO.getRefundNo())) {
                    LOGGER.error("OrderRefundSuccessHandler#callBackHandler refund no not exit error refundDO:{}", JSON.toJSONString(refundDO));
                    return false;
                }

                refundOrder = refundDomainMapper.selectByRefundNo(refundDO.getRefundNo());

                if(refundOrder == null) {
                    LOGGER.error("OrderRefundSuccessHandler#callBackHandler refund order not exit error refundDO:{}", JSON.toJSONString(refundDO));
                    return false;
                }

                LOGGER.warn("OrderRefundSuccessHandler#callBackHandler refund order status error refundDO:{}", JSON.toJSONString(refundDO));
                refundOrder.setChannelRefundNo(refundDO.getId());
            }

            if(refundDO.getSucceed()) {
                refundOrder.setStatus(RefundOrder.STATUS_FINISH);
                refundOrder.setSuccessTime(refundDO.getTimeSucceed());
            }
            else {
                // 退款失败
                LOGGER.error("OrderRefundSuccessHandler#callBackHandler refund status not success refundDO:{}", JSON.toJSONString(refundDO));

                if(RefundOrder.STATUS_FAIL.equals(refundDO.getStatus())) {
                    refundOrder.setStatus(refundDO.getStatus());
                }
                else if(RefundOrder.STATUS_CLOSED.equals(refundDO.getStatus())) {
                    refundOrder.setStatus(refundDO.getStatus());
                }
                else {
                    // 无法识别的状态
                    LOGGER.error("OrderRefundSuccessHandler#callBackHandler refund status not found refundDO:{}", JSON.toJSONString(refundDO));
                    return true;
                }
            }

            int count = refundDomainMapper.updateStatusByRefundNo(refundOrder.getRefundNo(), refundOrder.getChannelRefundNo(), refundOrder.getSuccessTime(), refundOrder.getUpdateTime(), refundOrder.getStatus(), refundOrder.getChannelTransactionNo(), refundOrder.getVersion());

            if(count < 1) {
                LOGGER.error("OrderRefundSuccessHandler#callBackHandler update sql error refundDO:{}", JSON.toJSONString(refundDO));
            }

            Long unixTime = refundOrder.getSuccessTime().getTime() / 1000;
            PayResultOrder payResultOrder = payResultOrderMapper.selectByPayNoAndChannel(refundOrder.getPayNo(), refundOrder.getChannel());

            if(refundDO.getSucceed()) {
                // 异步回调
                callbackRunner.callback(refundDO.getRefundNo(), CallbackResultVo.TYPE_REFUND_SUCCESS, refundOrder.getAmount(), unixTime, refundOrder.getCallbackAddress(), payResultOrder.getMerchantId(), refundOrder.getBusinessRefundNo());

                try {
                    // 垫付退款回补
                    returnAdvance(refundOrder, payResultOrder);
                }
                catch(Exception ex) {
                    LOGGER.error(ex.getMessage(), ex);
                }

                // 异步处理渠道充值撤销
                if(refundOrder.getChannel().contains(Constants.CHANNEL_DIRECT_NAME) || Constants.thirdChannelSubmitPingan(refundOrder.getChannel())) {
                    RechargeHandleDto rechargeHandleDto = RechargeHandleDto.builder().
                            rechargeType(RechargeHandleDto.REFUND).
                            channel(refundOrder.getChannel()).
                            orderNo(refundOrder.getRefundNo()).
                            accountId(refundOrder.getUserId()).
                            build();
                    callbackRunner.syncSendMsg(RocketMqTopic.TOPIC_RECHARGE_HANDLE, rechargeHandleDto);
                }
            }
            else {
                String failMsg = (StringUtils.isBlank(refundDO.getFailureCode()) ? "" : refundDO.getFailureCode()) + ":" + (StringUtils.isBlank(refundDO.getFailureMsg()) ? "" : refundDO.getFailureMsg());
                // 异步回调
                callbackRunner.callback(refundDO.getRefundNo(), CallbackResultVo.TYPE_REFUND_FAIL, refundOrder.getAmount(), 0L, refundOrder.getCallbackAddress(), payResultOrder.getMerchantId(), refundOrder.getBusinessRefundNo(), failMsg);
            }

            return true;
        }
        catch(Exception e) {
            LOGGER.error("OrderRefundSuccessHandler callBackHandler domain:{}", JSON.toJSON(domain));
            return false;
        }
    }

    /**
     * 垫付退款回补
     * @param refundOrder
     */
    private void returnAdvance(RefundOrder refundOrder, PayResultOrder payResultOrder) {
        LOGGER.info("OrderRefundHandler#returnAdvance, refundOrder={}" , JSONUtils.toJSON(refundOrder));

        // 退款成功
        if(!RefundOrder.STATUS_FINISH.equals(refundOrder.getStatus())) {
            LOGGER.error("OrderRefundHandler#returnAdvance, ignore01, refundNo={}", refundOrder.getRefundNo());
        }

        // 荷叶富民需要回扣
        if(!payResultOrder.getBusinessOrderType().contains(BusinessTypeEnum.YIKUAIQIAN.getType()) ||
                !payResultOrder.getPayChannel().contains(ChannelTypeEnum.FM.getCode()))
        {
            LOGGER.error("OrderRefundHandler#returnAdvance, ignore02, refundNo={}", refundOrder.getRefundNo());
            return;
        }

        RefundReturnAdvance returnAdvance = refundReturnAdvanceService.selectByRefundNo(refundOrder.getRefundNo());

        if(returnAdvance != null && !CommonStatusEnum.FAILED.getCode().equals(returnAdvance.getStatus())) {
            LOGGER.error("OrderRefundHandler#returnAdvance, repeat, refundNo={}", refundOrder.getRefundNo());
            return;
        }

        // 1.插入退款回补单
        if(returnAdvance == null) {
            returnAdvance = new RefundReturnAdvance();
            returnAdvance.setChannel(payResultOrder.getPayChannel());
            returnAdvance.setBusinessType(payResultOrder.getBusinessType());
            returnAdvance.setBusinessOrderType(payResultOrder.getBusinessOrderType());
            returnAdvance.setRefundNo(refundOrder.getRefundNo());
            returnAdvance.setReturnAdvanceNo(leafUtil.getSnowflakeId());
            returnAdvance.setReturnAmount(refundOrder.getAmount());
            // 出金
            returnAdvance.setPayerAccount("yikuaiqian_fm_platform");
            // 入金
            returnAdvance.setPayeeAccount("heye_refund_charge");
        }

        returnAdvance.setStatus(CommonStatusEnum.PROCESSING.getCode());
        returnAdvance.setMessage(CommonStatusEnum.PROCESSING.getMessage());
        refundReturnAdvanceService.insertOrUpdate(returnAdvance);

        try {
            // 2.回补
            SeparateAccountFromUserVo account = new SeparateAccountFromUserVo();
            account.setBusinessOrderNo(returnAdvance.getReturnAdvanceNo());
            account.setBusinessType(payResultOrder.getBusinessType());
            account.setBusinessIdType(payResultOrder.getBusinessOrderType());
            account.setBusinessOrderType(payResultOrder.getBusinessOrderType());
            account.setBusinessUserIdOut(returnAdvance.getPayerAccount());
            account.setBusinessUserIdIn(returnAdvance.getPayeeAccount());
            account.setBusinessIdTypeOut(BusinessIdTypeEnum.YIKUAIQIAN_FM.getType());
            account.setBusinessIdTypeIn(BusinessIdTypeEnum.YIKUAIQIAN_FM.getType());
            account.setAmount(refundOrder.getAmount());
            account.setInvoker(StringUtils.EMPTY);
            account.setExtra("垫付退款回补");
            ResultVO<SeparateAccountsBo> result = paymentOrderApi.separateAccountFromUser(account, StringUtils.EMPTY);

            // 3.更新退款回补单
            if(result.isSuccess()) {
                returnAdvance.setStatus(CommonStatusEnum.SUCCESS.getCode());
                returnAdvance.setMessage(CommonStatusEnum.SUCCESS.getMessage());
            }
            else {
                returnAdvance.setStatus(CommonStatusEnum.FAILED.getCode());
                returnAdvance.setMessage(StringUtils.isBlank(result.getMsg()) ? CommonStatusEnum.SUCCESS.getMessage() : result.getMsg());
            }
        }
        catch(Exception ex) {
            LOGGER.error(ex.getMessage() ,ex);
            returnAdvance.setStatus(CommonStatusEnum.FAILED.getCode());
            returnAdvance.setMessage(ex.getMessage());
        }

        LOGGER.info("OrderRefundHandler#returnAdvance, returnAdvance={}" , JSONUtils.toJSON(returnAdvance));
        refundReturnAdvanceService.updateStatusById(returnAdvance);
    }
}
